﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

using NUnit.Framework;
using Nemerle2.Compiler;

namespace Test
{
  /// <summary>
  /// Description of MethodTests.
  /// </summary>
  [TestFixture]
  public class PropertyTests : AssemblyTests
  {
    private mutable _methodTestsClass : ITypeInfo;
    private mutable _methodTestsStaticClass : ITypeInfo;

    [SetUp]
    public Prepare() : void
    {
      _methodTestsClass = CommonProject.LoadedAssemblies.First().TopLevelTypes.Where(ty => ty.Name == typeof(TestAssembly.MethodTestsClass).Name).First();
      _methodTestsStaticClass = CommonProject.LoadedAssemblies.First().TopLevelTypes.Where(ty => ty.Name == typeof(TestAssembly.MethodTestsStaticClass).Name).First();

      Assert.NotNull(_methodTestsClass);
    }

    [Test]
    public Test() : void
    {
      def findMethod(ty : ITypeInfo, name : string): IMethodInfo
      {
        ty.GetMembers().First(member => member.Name == name && member.MemberKind == MemberKind.Method) :> IMethodInfo;
      }

      def ty = _methodTestsClass;
      def method = findMethod(ty, "SimpleMethodWithoutParams");
      def isValidSig =
        match (method.FunType)
        {
          | (FixedType.Tuple([]), FixedType.Void) => true
          | _ => false;
        };

      Assert.IsTrue (isValidSig, "Unexpected method signature");
      Assert.IsFalse(method.IsStatic);
      Assert.IsFalse(method.IsConstructor);
      Assert.IsFalse(method.IsFinal);

      def method = findMethod(ty, "StaticMethod");
      Assert.IsTrue (method.IsStatic);
      Assert.IsFalse(method.IsConstructor);
      Assert.IsFalse(method.IsFinal);
      def isValidSig =
        match (method.FunType)
        {
          | (FixedType.Tuple(_ :: []), FixedType.Class(_, [])) => true
          | _ => false;
        };
      Assert.IsTrue(isValidSig, "Unexpected method signature");
      def ctors = ty.GetMembers().Where(m => m.MemberKind == MemberKind.Constructor).ToArray();
      def ctors2 = ty.GetConstructors(NBindingFlags.Public);
      Assert.GreaterOrEqual(2, ctors.Length);
      Assert.AreEqual(ctors.Length, ctors2.Count());
    }

    [Test]
    public TestIsObsolete() : void
    {
      def methods = _methodTestsClass.FindMethod("ObsoleteMethod", NBindingFlags.Public);
      Assert.AreNotEqual(0, methods.Length);
      Assert.IsTrue(methods.Head.IsObsolete, "Error in detect obsolete method");

      def methods = _methodTestsClass.FindMethod("MethodWithArray", NBindingFlags.Public);
      Assert.AreNotEqual(0, methods.Length);
      Assert.IsFalse(methods.Head.IsObsolete, "Error in detect obsolete method");
    }

    [Test]
    public TestExtension() : void
    {
      def methods = _methodTestsStaticClass.FindMethod("ExtensionMethod", NBindingFlags.Public | NBindingFlags.Static);
      Assert.AreNotEqual(0, methods.Length);
      Assert.True(methods.Head.IsExtension, "Error in detect extension method");
    }

    [Test]
    public TestFunType() : void
    {
      mutable methods = _methodTestsClass.FindMethod("MethodWithArray", NBindingFlags.Public);
      Assert.AreNotEqual(0, methods.Length);
      def funType = methods.Head.FunType;
      Assert.NotNull(funType);
      //TODO: check result

      methods = _methodTestsClass.FindMethod("MethodWithFunc", NBindingFlags.Public);
      Assert.AreNotEqual(0, methods.Length);
      Assert.NotNull(methods.Head.FunType);
      //TODO: check result

      methods = _methodTestsClass.FindMethod("HeavyMethod", NBindingFlags.Public);
      Assert.AreNotEqual(0, methods.Length);
      Assert.NotNull(methods.Head.FunType);


    }
  }
}
